package com.example.client;

import com.example.decoder.RpcDecoder;
import com.example.encoder.RpcEncoder;
import com.example.handler.UserServiceClientHandler;
import com.example.request.RpcRequest;
import com.example.serialization.JSONSerializer;
import io.netty.bootstrap.Bootstrap;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.codec.string.StringDecoder;

import java.lang.reflect.Proxy;
import java.util.UUID;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * @author lbq
 * @version 1.0
 * @date 2021/2/4 21:28
 */
public class RPCConsumer {

    private static final ExecutorService executorService = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors());

    private static UserServiceClientHandler userServiceClientHandler;

    public static void initClient() throws InterruptedException {
        userServiceClientHandler = new UserServiceClientHandler();

        NioEventLoopGroup group = new NioEventLoopGroup();
        Bootstrap bootstrap = new Bootstrap();
        bootstrap.group(group)
                .channel(NioSocketChannel.class)
                .option(ChannelOption.TCP_NODELAY, true)
                .handler(new ChannelInitializer<SocketChannel>() {
                    @Override
                    protected void initChannel(SocketChannel socketChannel) throws Exception {
                        ChannelPipeline pipeline = socketChannel.pipeline();
                        pipeline.addLast(new RpcEncoder(RpcRequest.class, new JSONSerializer()));
                        pipeline.addLast(new StringDecoder());
                        pipeline.addLast(userServiceClientHandler);
                    }
                });

        bootstrap.connect("127.0.0.1", 8999).sync();
    }

    public Object createProxy(Class<?> serviceClass) {
        return Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(),
                new Class[]{serviceClass}, (proxy, method, args) -> {
                    if (userServiceClientHandler == null) {
                        initClient();
                    }
                    RpcRequest rpcRequest = new RpcRequest();
                    String uuid = UUID.randomUUID().toString();
                    System.out.println(uuid);
                    rpcRequest.setRequestId(uuid);
                    String className = serviceClass.getName();
                    System.out.println(className);
                    rpcRequest.setClassName(className);
                    rpcRequest.setMethodName(method.getName());
                    Class<?>[] parameterTypes = method.getParameterTypes();
                    rpcRequest.setParameterTypes(parameterTypes);
                    rpcRequest.setParameters(args);
                    userServiceClientHandler.setParam(rpcRequest);
                    return executorService.submit(userServiceClientHandler).get();
                });
    }
}
